/**
 * 
 */
package implementation;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;

import javax.swing.JOptionPane;

import operands.Operand;
import operators.Operator;

/**
* <br><b>TokenStacks</b>s Class that encapsulates the 2Stack algorithm used for parsing an mathematical
* expression and computing the operator precedence </br>
* <b>Extends</b> JFrame
* @author Alexandra Tarca
* @version 1.6
* @since 3/5/2011
*/
public class TokenStacks {
	/**Operators list*/
	private ArrayList<String> operators;
	/**Operands list*/
	private ArrayList<String> operands;
	/**Operator power map*/
	private HashMap<String,Integer> operProps;
	/**Operators stack*/
	ArrayList<Node> opStack;
	/**Operands stack*/
	ArrayList<Node> orStack;
	/**
	 *<b>Constructor</b>
	 *creates an empty tokenStack object (empty==operators and operands stack are initialized but
	 *have no values in them) 
	 *<b>Initializes operator properties with the according powers</b>
	 */
	public TokenStacks() {
		operProps=new HashMap<String, Integer>();
		operProps.put("#",0);
		operProps.put("+",1);
		operProps.put("-",1);
		operProps.put("*",2);
		operProps.put("/",2);
		
		opStack=new ArrayList<Node>();
		orStack=new ArrayList<Node>();
		operators=new ArrayList<String>();
		operands=new ArrayList<String>();
	}
	
	/**
	 * Function that prepares the object for further reuse
	 * (an instance of this class can be used for parsing 
	 * multiple expressions without re-initialization )
	 * */
	private void cleanLists(){
		operands.clear();
		operators.clear();
	}
	/**
	*Parses the given expression
	*@param exp - string to parse 
	*/
	public void parseExpression(String exp){
		cleanLists();
		operators.add("#");
		
		StringTokenizer tok = new StringTokenizer(exp, "+*-/");
		while (tok.hasMoreElements())
			operands.add((String)(tok.nextElement()));
		
		String opStr = new String();
		for (String i : operands)
			opStr+=i;

		tok = new StringTokenizer(exp, opStr);
		while (tok.hasMoreElements())
			operators.add((String)(tok.nextElement()));
		operators.add("#");
	}
	
	/**
	 * <b>Creates the tree resulting form the expression</b>
	 * @return the resulting parse tree
	 */
	public Node createTree() {
		try{
			Node n = new Operator("");
			orStack.add(new Operand(operands.get(0)));
			operands.remove(0);
			opStack.add(new Operator(operators.get(0)));
			operators.remove(0);
			
			while (true){
				if (opStack.size()==2)
					if (opStack.get(0).getContent().equals("#") && opStack.get(1).getContent().equals("#"))
						break;
						
				if (operands.size()>0){
					orStack.add(new Operand(operands.get(0)));
					operands.remove(0);
				}
					
				
				if (operProps.get(operators.get(0)) >= operProps.get(opStack.get(opStack.size()-1).getContent())){
					opStack.add(new Operator(operators.get(0)));
					operators.remove(0);
				}
				else {
					n = opStack.get(opStack.size()-1);
					opStack.remove(opStack.size()-1);
					n.setRight(orStack.get(orStack.size()-1));
					orStack.remove(orStack.size()-1);
					n.setLeft(orStack.get(orStack.size()-1));
					orStack.remove(orStack.size()-1);
					orStack.add(n);
				}
			}
			}
			catch (IndexOutOfBoundsException e){
				JOptionPane.showMessageDialog(null, e.getMessage());
				System.exit(1);
			}
		return orStack.get(0);
	}
	
	public ArrayList<String> getOperators() {
		return operators;
	}
	public ArrayList<String> getOperands() {
		return operands;
	}
}
